package com.cy.pj.common.aspect;

import com.cy.pj.common.annotation.RequiredLog;
import com.cy.pj.sys.entity.SysLog;
import com.cy.pj.sys.service.SysLogService;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Date;

@Aspect
@Component
@Slf4j
public class SysLogAspect {


    @Autowired
    private SysLogService sysLogService;

    @Pointcut("@annotation(com.cy.pj.common.annotation.RequiredLog)")
    public void doPointCut(){}

    @Around("doPointCut()")
    public Object around(ProceedingJoinPoint jp) throws Throwable {
        //记录方法执行的开始时间
        long t1 = System.currentTimeMillis();
        try{
            //调用目标方法
            Object result = jp.proceed();
            //记录方法执行的结束时间及总时长
            long t2 = System.currentTimeMillis();
            log.info("method execute time {}", t2 - t1);
            //将用户的正常行为信息写入到数据库
            saveLog(jp,t2-t1,null);
            return result;
        }catch (Throwable e){
            //出现异常时输出错误日志
            log.error("error is {}",e.getMessage());
            long t2 = System.currentTimeMillis();
            saveLog(jp,t2-t1,e);
            throw e;
        }
    }

    /**
     * 获取用户操作的详细信息
     */
    private void saveLog(ProceedingJoinPoint jp, long time,Throwable e) throws Exception{
        String username = "cgb";
        String ip = "192.168.126.129";
        //1.获取用户行为数据
        //获取目标对象类型
        Class<?> targetCls = jp.getTarget().getClass();
        //获取目标方法签名
        MethodSignature ms = (MethodSignature) jp.getSignature();
        //根据目标方法的名字和类型，拿到目标方法
        Method targetMethod = targetCls.getMethod(ms.getName(), ms.getParameterTypes());
        //获取注解中的操作名
        RequiredLog annotation = targetMethod.getAnnotation(RequiredLog.class);
        String operation = "operation";
        if(annotation != null) {
            operation = annotation.operation();
        }
        //获取方法声明(类全名+方法名)
        String classMethodName = targetCls.getName() + "." + targetMethod.getName();
        //获取方法的实际参数
        Object[] args = jp.getArgs();
        String params = new ObjectMapper().writeValueAsString(args);
        //2.封装用户行为日志
        SysLog syslog = new SysLog();
        //获取当前执行时间
        syslog.setIp(ip).setUsername(username).setOperation(operation)
                .setMethod(classMethodName).setParams(params).setTime(time).setCreatedTime(new Date());
        //3.保存到数据库
        sysLogService.saveObject(syslog);
    }
}
